package com.idol.logger.core.printer.file

import java.util.concurrent.Executor
import java.util.concurrent.Executors
import java.util.concurrent.LinkedBlockingQueue

internal class IdolPrintWorker<T>(
    private val block: (T) -> Unit,     // task
    service: Executor? = null,          // threads pool.
    lock: Any? = null                   // lock object.
) : Runnable {

    private val lock = lock ?: Any()
    private val executor = service ?: Executors.newSingleThreadExecutor()

    private var running: Boolean = false
    private val queue by lazy { LinkedBlockingQueue<T>() }

    /**
     * is running.
     */
    fun isRunning() = synchronized(lock) { running }

    /**
     * add data to queue, The data will be an param to run the block.
     */
    fun put(data: T) = also {
        try {
            queue.put(data)
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
    }

    /**
     * start task.
     */
    fun start() = also {
        if (!running) {
            synchronized(lock) {
                if (!running) {
                    executor.execute(this)
                    running = true
                }
            }
        }
    }

    /**
     * stop task, the task can`t be stopped immediately.
     */
    fun stop() {
        if (running) {
            synchronized(lock) {
                running = false
            }
        }
    }

    override fun run() {
        try {
            while (isRunning() && !queue.isEmpty()) {
                block.invoke(queue.take())
            }
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
        synchronized(this) { running = false }
    }
}